<?php
namespace Particle\Core;

/**
 * 
 * @package Particle
 * @category Core
 * @author dertin
 * 
 **/
final class Security {

    private final static function array_map_recursive($fn, $arr,$recursive=false) {
        $rarr = array();
        
        foreach ($arr as $k => $v) {
                $rarr[$k] = is_array($v) ? self::array_map_recursive($fn, $v, true) : call_user_func($fn, $v);
        }
        
        if($recursive){
            return $rarr;
        }else{
            return $rarr[0];
        }
        
    }

    public final static function filterInt($int, $default = 0) {

        $int = (int) $int;

        if (is_int($int)) {
            return $int;
        } else {
            return $default;
        }
    }

    public final static function filterAlphaNum($str, $default = '') {

        if (is_string($str)) {
            $filterStr = (string) preg_replace('/[^A-Z0-9_]/i', '', $str);
            return trim($filterStr);
        } else {
            return $default;
        }
    }

    public final static function htmlescape($strHtml, $remove=false, $default = '', $allowable_tags=null) {

        if (is_string($strHtml)) {
            if($remove){
                $filterStrHtml = strip_tags($strHtml, $allowable_tags);
            }else{
                $filterStrHtml = htmlspecialchars($strHtml, ENT_QUOTES, CHARSET);
            }
            return $filterStrHtml;
        } else {
            return $default;
        }
    }
    
    public final static function cleanHtml($filterHtml, $remove=false, $default = '', $allowable_tags=null) {

        if (is_array($filterHtml)) {
            $filterHtml = self::array_map_recursive(array('Particle\Core\Security', 'htmlescape'), array($filterHtml, $remove, $default, $allowable_tags));
        } else if (is_string($filterHtml)) {
            $filterHtml = self::htmlescape($filterHtml, $remove, $default, $allowable_tags);
        } else {
            return $default;
        }

        return $filterHtml;
    }

    public final static function filterSql($sql, $html = true, $default = false) {

        if (isset($sql) && !empty($sql) && is_string($sql)) {

            if ($html) {
                if (DOCTYPE == 'HTML5') {
                    $iDocType = ENT_HTML5;
                } else if (DOCTYPE == 'XHTML') {
                    $iDocType = ENT_XHTML;
                } else {
                    $iDocType = ENT_HTML401;
                }

                $sql = htmlspecialchars($sql, ENT_NOQUOTES | $iDocType, CHARSET);
            }

            if (!get_magic_quotes_gpc()) {
                $sql = addslashes($sql);
            }

            return trim($sql);
        } else {
            return $default;
        }
    }

    public final static function validateEmail($email) {

        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            return false;
        }

        return true;
    }

    public final static function filterXSStext($valXSS, $default = '') {

        if (!isset($valXSS) || empty($valXSS) || !is_string($valXSS)) {
            return $default;
        }

        $valTrim = trim($valXSS);

         // Fix &entity\n;
        $data = str_replace(array('&amp;','&lt;','&gt;'), array('&amp;amp;','&amp;lt;','&amp;gt;'), $valTrim);
        $data = preg_replace('/(&#*\w+)[\x00-\x20]+;/u', '$1;', $data);
        $data = preg_replace('/(&#x*[0-9A-F]+);*/iu', '$1;', $data);
        $data = html_entity_decode($data, ENT_COMPAT, 'UTF-8');

        // Remove any attribute starting with "on" or xmlns
        $data = preg_replace('#(<[^>]+?[\x00-\x20"\'])(?:on|xmlns)[^>]*+>#iu', '$1>', $data);

        // Remove javascript: and vbscript: protocols
        $data = preg_replace('#([a-z]*)[\x00-\x20]*=[\x00-\x20]*([`\'"]*)[\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2nojavascript...', $data);
        $data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2novbscript...', $data);
        $data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#u', '$1=$2nomozbinding...', $data);

        // Only works in IE: <span style="width: expression(alert('Ping!'));"></span>
        $data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?expression[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
        $data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?behaviour[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
        $data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:*[^>]*+>#iu', '$1>', $data);

        // Remove namespaced elements (we do not need them)
        $data = preg_replace('#</*\w+:\w[^>]*+>#i', '', $data);

        do
        {
        // Remove really unwanted tags
        $old_data = $data;
        $data = preg_replace('#</*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|i(?:frame|layer)|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|title|xml)[^>]*+>#i', '', $data);
        }
        while ($old_data !== $data);

        $valNoXSS = strip_tags($data);

        return $valNoXSS;
    }

    public final static function filterXSS($valXSS, $default = '') {
        
        if (is_array($valXSS)) {
            $valXSS = self::array_map_recursive(array('Particle\Core\Security', 'filterXSStext'), array($valXSS, $default));
        } else if (is_string($valXSS)) {
            $valXSS = self::filterXSStext($valXSS, $default);
        } else {
            return $default;
        }

        return $valXSS;
    }

}